#-*-coding:UTF-8-*-

__author__='zhaoxp'

import socket
import thread
import threading
import select
import signal
import sys
import os
import time
import traceback


SOCKET_PAIRS={}
SOCKET_CLOSE_SIGN={}

TIME_OUT=600

def quit_signal_handler(signum,frame):
    print('signal number = '+str(signum))
    print('singal frame  = '+str(frame))
    print('close all connections')
    for k,v in SOCKET_PAIRS.items():
        print('%s <-----> %s'%(k,v))
        try:
            k.close()
            #k.shutdown(socket.SHUT_RDWR)
        except Exception as ex:
            print('exception %s'%ex)
            traceback.print_exc()
        try:
            v.close()
            #v.shutdown(socket.SHUT_RDWR)
        except Exception as ex:
            print('exception %s'%ex)
            traceback.print_exc()
    print('--------------------sys.exit()--------------------')
    sys.exit()
    #print('--------------------os._exit()--------------------')
    #os._exit()


def channel_to_outer(sock_inner,sock_outer):
    print('another socket %s'%sock_inner)
    buf=bytearray(1024)
    sock_inner.settimeout(TIME_OUT)
    while True:
        try:
            '''
            size=sock_inner.recv_into(buf)
            #print('channel to outer recv size = %d'%size)
            if size>0:
                sock_outer.sendall(buf[:size])
                #print('channel to outer recv data = %s'%buf[0:size])
            else:
                break
            '''
            data=sock_inner.recv(1024)
            if data:
                sock_outer.sendall(data)
            else:
                break
        except socket.timeout:
            if SOCKET_CLOSE_SIGN[sock_inner]:
                del SOCKET_CLOSE_SIGN[sock_inner]
                print('timeout, break and sock_inner close')
                break
    try:
        sock_inner.close()
        #sock_inner.shutdown(socket.SHUT_RDWR)
    except Exception as ex:
        print('exception of sock_inner %s'%ex)
        traceback.print_exc()
    print('close inner socket %s '%sock_inner)
    #sock_inner.close()
    #print('close inner socket %s '%sock_inner)


def socket_data_exchange(sock_outer,addr,dest_port):
    print('new connection is %s'%sock_outer)
    sock_inner=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock_inner.connect(('127.0.0.1',dest_port))

    t=threading.Thread(target=channel_to_outer,args=(sock_inner,sock_outer))
    t.setDaemon(True)
    t.start()
    SOCKET_PAIRS[sock_outer]=sock_inner
    SOCKET_CLOSE_SIGN[sock_inner]=False
    # channel into local
    #print('channel to local ...')
    buf=bytearray(1024)
    while True:
        '''
        size=sock_outer.recv_into(buf)
        #print('channel to local recv size = %d'%size)
        if size>0:
            sock_inner.sendall(buf[:size])
            #print('channel to local recv data = %s'%buf[0:size])
        else:
            break
        '''
        data=sock_outer.recv(1024)
        if data:
            sock_inner.sendall(data)
        else:
            break
    try:
        sock_outer.close()
        #sock_outer.shutdown(socket.SHUT_RDWR)
    except Exception as ex:
        print('exception of sock_outer %s'%ex)
        traceback.print_exc()
    print('close outer socket %s '%sock_outer)
    del SOCKET_PAIRS[sock_outer]
    SOCKET_CLOSE_SIGN[sock_inner]=True
    

def start_to_accept_data(src_port,dest_port):
    server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    server_socket.bind(('0.0.0.0',src_port))
    server_socket.listen(10)
    while True:
        sock,addr=server_socket.accept()
        print('\naccept %s and addr is %s'%(sock,addr))
        #t=threading.Thread(target=socket_data_exchange,args=(sock,addr,dest_port))
        #t.start()
        #thread.start_new_thread(socket_data_exchange,(sock,addr,dest_port))
        t=threading.Thread(target=socket_data_exchange,args=(sock,addr,dest_port))
        t.setDaemon(True)
        t.start()


def get_argv():
    argv=sys.argv
    from_port=1022
    to_port=22
    if len(argv)==3:
        try:
            from_port=int(argv[1])
            to_port=int(argv[2])
            if from_port==to_port:
                raise Exception("same ports")
        except:
            print('argvs not correct %s'%argv)
            print('argvs format: <source port> <dest port>')
    elif len(argv)!=1:
        print('argv number not correct %s'%argv)
    return [from_port,to_port]


if __name__=='__main__':
    argv=get_argv()
    signal.signal(signal.SIGINT,quit_signal_handler)
    #thread.start_new_thread(start_to_accept_data,(argv[0],argv[1]))
    t=threading.Thread(target=start_to_accept_data,args=(argv[0],argv[1]))
    t.setDaemon(True)
    t.start()
    while True:
        print('active Thread() count = %s'%threading.active_count())
        time.sleep(600)
    